package cn.lingyangwl.agile.ram;

import cn.lingyangwl.agile.ram.model.ResourceSyncResp;
import cn.lingyangwl.framework.core.response.Resp;
import cn.lingyangwl.framework.core.response.RetOps;
import cn.lingyangwl.framework.core.utils.servlet.ServletUtils;
import cn.lingyangwl.framework.tool.core.CollectionUtils;
import cn.lingyangwl.framework.tool.core.exception.BizException;
import cn.lingyangwl.agile.model.constants.CommonCons;
import cn.lingyangwl.agile.model.constants.RequestCons;
import cn.lingyangwl.agile.model.constants.SecurityCons;
import cn.lingyangwl.agile.model.module.auth.LoginUserHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.function.BiConsumer;

/**
 * @author shenguangyang
 */
@Slf4j
@Service
public class RamSdkApiImpl implements RamSdkApi {
    @Resource
    private DiscoveryClient discoveryClient;

    @Resource
    private RestTemplate restTemplate;

    @Resource(name = "myThreadPool")
    private ThreadPoolTaskExecutor myThreadPool;
    @Override
    public List<String> listSyncResource(BiConsumer<String, List<ResourceSyncResp>> consumer) {
        List<String> services = discoveryClient.getServices();
        List<String> errorData = new CopyOnWriteArrayList<>();
        HttpServletRequest request = ServletUtils.getRequestOfNonNull();
        CountDownLatch countDownLatch = new CountDownLatch(services.size());
        for (String serviceId : services) {
            myThreadPool.execute(() -> {
                try {
                    List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
                    if (CollectionUtils.isEmpty(instances)) {
                        return;
                    }
                    ServiceInstance instance = instances.get(0);
                    String url = CommonCons.HTTP + String.format("%s:%s/%s", instance.getHost(), instance.getPort(), RamSdkCons.API_LIST_SYNC_RESOURCE);
                    HttpHeaders requestHeaders = new HttpHeaders();
                    requestHeaders.set(RequestCons.Headers.APP_ID, request.getHeader(RequestCons.Headers.APP_ID));
                    requestHeaders.set(RequestCons.Headers.SYSTEM_TYPE, request.getHeader(RequestCons.Headers.SYSTEM_TYPE));
                    requestHeaders.set(RequestCons.Headers.TENANT_ID, request.getHeader(RequestCons.Headers.TENANT_ID));
                    requestHeaders.set(RequestCons.Headers.LOGIN_USER, LoginUserHolder.get().encodeToString());

                    HttpEntity<?> requestEntity = new HttpEntity<>(requestHeaders);

                    ResponseEntity<Resp<List<ResourceSyncResp>>> response = restTemplate.exchange(
                            url, HttpMethod.POST, requestEntity, new ParameterizedTypeReference<Resp<List<ResourceSyncResp>>>() {});
                    if (Objects.isNull(response.getBody()) || !RetOps.of(response.getBody()).isSuccess()) {
                        errorData.add(serviceId);
                        return;
                    }
                    List<ResourceSyncResp> rsList = response.getBody().getData();
                    consumer.accept(serviceId, rsList);
                } catch (Exception e) {
                    log.error("errorMsg: {}", e.getMessage());
                } finally {
                    countDownLatch.countDown();
                }
            });

        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            throw new BizException("系统繁忙");
        }
        return errorData;
    }
}
